package util;

import org.apache.commons.lang3.StringUtils;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
import org.codehaus.jackson.type.JavaType;
import org.codehaus.jackson.type.TypeReference;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Jackson工具类
 *
 * @author suddev
 * @create 2017-11-25 2:18 PM
 **/
public class JsonUtil {

    private static ObjectMapper objectMapper = new ObjectMapper();

    static {
        // 对象字段全部列入
        objectMapper.setSerializationInclusion(Inclusion.NON_DEFAULT);

        // 取消默认转换timestamps形式
        objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);

        // 忽略空bean转json的错误
        objectMapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);

        // 统一日期格式yyyy-MM-dd HH:mm:ss
        // objectMapper.setDateFormat(new SimpleDateFormat(DateTimeUtil.STANDARD_FORMAT));

        // 忽略在json字符串中存在,但是在java对象中不存在对应属性的情况
        objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }


    /**
     * 获取利用反射获取类里面的值和名称
     *
     * @param obj
     * @return
     * @throws IllegalAccessException
     */
    public static Map<Object, Object> objectToMap(Object obj) throws IllegalAccessException {
        Map<Object, Object> map = new HashMap<Object, Object>();
        Class<?> clazz = obj.getClass();
        System.out.println(clazz);
        for (Field field : clazz.getDeclaredFields()) {
            field.setAccessible(true);
            String fieldName = field.getName();
            Object value = field.get(obj);
            map.put(fieldName, value);
        }
        return map;
    }


    /**
     * Object转json字符串
     *
     * @param obj
     * @param <T>
     * @return
     */
    public static <T> String obj2String(T obj) {
        if (obj == null) {
            return null;
        }
        try {
            return obj instanceof String ? (String) obj : objectMapper.writeValueAsString(obj);
        } catch (Exception e) {
            System.out.println("Parse object to String error");
            e.printStackTrace();
            return null;
        }
    }

    /**
     * Object转json字符串并格式化美化
     *
     * @param obj
     * @param <T>
     * @return
     */
    public static <T> String obj2StringPretty(T obj) {
        if (obj == null) {
            return null;
        }
        try {
            return obj instanceof String ? (String) obj : objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        } catch (Exception e) {
            System.out.println("Parse object to String error");
            e.printStackTrace();
            return null;
        }
    }

    /**
     * string转object
     *
     * @param str   json字符串
     * @param clazz 被转对象class
     * @param <T>
     * @return
     */
    public static <T> T string2Obj(String str, Class<T> clazz) {
        if (StringUtils.isEmpty(str) || clazz == null) {
            return null;
        }
        try {
            return clazz.equals(String.class) ? (T) str : objectMapper.readValue(str, clazz);
        } catch (IOException e) {
            System.out.println("Parse String to Object error");
            e.printStackTrace();
            return null;
        }
    }

    /**
     * string转object
     *
     * @param str           json字符串
     * @param typeReference 被转对象引用类型
     * @param <T>
     * @return
     */
    public static <T> T string2Obj(String str, TypeReference<T> typeReference) {
        if (StringUtils.isEmpty(str) || typeReference == null) {
            return null;
        }
        try {
            return (T) (typeReference.getType().equals(String.class) ? str : objectMapper.readValue(str, typeReference));
        } catch (IOException e) {
            System.out.println("Parse String to Object error");
            e.printStackTrace();
            return null;
        }
    }

    /**
     * string转object 用于转为集合对象
     *
     * @param str             json字符串
     * @param collectionClass 被转集合class
     * @param elementClasses  被转集合中对象类型class
     * @param <T>
     * @return
     */
    public static <T> T string2Obj(String str, Class<?> collectionClass, Class<?>... elementClasses) {
        JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
        try {
            return objectMapper.readValue(str, javaType);
        } catch (IOException e) {
            System.out.println("Parse String to Object error");
            e.printStackTrace();
            return null;
        }
    }

    public static String toJson(final Object o) {
        if (o == null) {
            return "\"\"";
        }
        if (o instanceof Date) {
            return date2JSon(o);
        }
        if (o instanceof Timestamp) {
            return timestamp2JSon(o);
        }
        if (o instanceof String) //String
        {
            return string2Json((String) o);
        }
        if (o instanceof Character) {
            return string2Json(String.valueOf(o));
        }
        if (o instanceof Boolean) //Boolean
        {
            return boolean2Json((Boolean) o);
        }
        if (o instanceof BigDecimal) //Boolean
        {
            return bigDecimal2Json((BigDecimal) o);
        }
        if (o instanceof Number) //Number
        {
            return number2Json((Number) o);
        }
        if (o instanceof Map) //Map
        {
            return map2Json((Map<Object, Object>) o);
        }
        if (o instanceof Collection) //List  Set
        {
            return collection2Json((Collection) o);
        }
        if (o instanceof Object[]) //对象数组
        {
            return array2Json((Object[]) o);
        }

        if (o instanceof int[])//基本类型数组
        {
            return intArray2Json((int[]) o);
        }
        if (o instanceof boolean[])//基本类型数组
        {
            return booleanArray2Json((boolean[]) o);
        }
        if (o instanceof long[])//基本类型数组
        {
            return longArray2Json((long[]) o);
        }
        if (o instanceof float[])//基本类型数组
        {
            return floatArray2Json((float[]) o);
        }
        if (o instanceof double[])//基本类型数组
        {
            return doubleArray2Json((double[]) o);
        }
        if (o instanceof short[])//基本类型数组
        {
            return shortArray2Json((short[]) o);
        }
        if (o instanceof byte[])//基本类型数组
        {
            return byteArray2Json((byte[]) o);
        }
        if (o instanceof Object) //保底收尾对象
        {
            return object2Json(o);
        }

        throw new RuntimeException("不支持的类型: " + o.getClass().getName());
    }

    private static String bigDecimal2Json(BigDecimal o) {
        o = o.setScale(2, BigDecimal.ROUND_HALF_UP);
        return "\"" + String.valueOf(o) + "\"";
    }

    private static String timestamp2JSon(Object o) {
        if (null == o) {
            return "\"\"";
        }
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return "\"" + formatter.format(o) + "\"";
    }

    private static String date2JSon(Object o) {
        if (null == o) {
            return "\"\"";
        }
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return "\"" + formatter.format(o) + "\"";
    }

    /**
     * 将 String 对象编码为 JSON格式，只需处理好特殊字符
     *
     * @param s String 对象
     * @return JSON格式
     */
    static String string2Json(final String s) {
        final StringBuilder sb = new StringBuilder();
        sb.append('\"');
        for (int i = 0; i < s.length(); i++) {
            final char c = s.charAt(i);
            switch (c) {
                case '\"':
                    sb.append("\\\"");
                    break;
                case '\\':
                    sb.append("\\\\");
                    break;
                case '/':
                    sb.append("\\/");
                    break;
                case '\b':
                    sb.append("\\b");
                    break;
                case '\f':
                    sb.append("\\f");
                    break;
                case '\n':
                    sb.append("\\n");
                    break;
                case '\r':
                    sb.append("\\r");
                    break;
                case '\t':
                    sb.append("\\t");
                    break;
                default:
                    sb.append(c);
            }
        }
        sb.append('\"');
        return sb.toString();
    }

    /**
     * 将 Number 表示为 JSON格式
     *
     * @param number Number
     * @return JSON格式
     */
    static String number2Json(final Number number) {
        return "\"" + number.toString() + "\"";
    }

    /**
     * 将 Boolean 表示为 JSON格式
     *
     * @param bool Boolean
     * @return JSON格式
     */
    static String boolean2Json(final Boolean bool) {
        return "\"" + bool.toString() + "\"";
    }

    /**
     * 将 Collection 编码为 JSON 格式 (List,Set)
     *
     * @param c
     * @return
     */
    static String collection2Json(final Collection<Object> c) {
        final Object[] arrObj = c.toArray();
        return toJson(arrObj);
    }

    /**
     * 将 Map<String, Object> 编码为 JSON 格式
     *
     * @param map
     * @return
     */
    static String map2Json(final Map<Object, Object> map) {
        if (map.isEmpty()) {
            return "{}";
        }
        final StringBuilder sb = new StringBuilder();
        sb.append('{');
        final Set<Object> keys = map.keySet();
        for (final Object key : keys) {
            final Object value = map.get(key);
            sb.append('\"');
            sb.append(String.valueOf(key).toUpperCase()); //不能包含特殊字符
            sb.append('\"');
            sb.append(':');
            sb.append(toJson(value)); //循环引用的对象会引发无限递归
            sb.append(',');
        }
        // 将最后的 ',' 变为 '}':
        sb.setCharAt(sb.length() - 1, '}');
        return sb.toString();
    }

    /**
     * 将数组编码为 JSON 格式
     *
     * @param array 数组
     * @return JSON 格式
     */
    static String array2Json(final Object[] array) {
        if (array.length == 0) {
            return "[]";
        }
        final StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (final Object o : array) {
            sb.append(toJson(o));
            sb.append(',');
        }
        // 将最后添加的 ',' 变为 ']':
        sb.setCharAt(sb.length() - 1, ']');
        return sb.toString();
    }

    static String intArray2Json(final int[] array) {
        if (array.length == 0) {
            return "[]";
        }
        final StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (final int o : array) {
            sb.append("\"" + Integer.toString(o) + "\"");
            sb.append(',');
        }
        // set last ',' to ']':
        sb.setCharAt(sb.length() - 1, ']');
        return sb.toString();
    }

    static String longArray2Json(final long[] array) {
        if (array.length == 0) {
            return "[]";
        }
        final StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (final long o : array) {
            sb.append("\"" + Long.toString(o) + "\"");
            sb.append(',');
        }
        // set last ',' to ']':
        sb.setCharAt(sb.length() - 1, ']');
        return sb.toString();
    }

    static String booleanArray2Json(final boolean[] array) {
        if (array.length == 0) {
            return "[]";
        }
        final StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (final boolean o : array) {
            sb.append("\"" + Boolean.toString(o) + "\"");
            sb.append(',');
        }
        // set last ',' to ']':
        sb.setCharAt(sb.length() - 1, ']');
        return sb.toString();
    }

    static String floatArray2Json(final float[] array) {
        if (array.length == 0) {
            return "[]";
        }
        final StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (final float o : array) {
            sb.append("\"" + Float.toString(o) + "\"");
            sb.append(',');
        }
        // set last ',' to ']':
        sb.setCharAt(sb.length() - 1, ']');
        return sb.toString();
    }

    static String doubleArray2Json(final double[] array) {
        if (array.length == 0) {
            return "[]";
        }
        final StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (final double o : array) {
            sb.append("\"" + Double.toString(o) + "\"");
            sb.append(',');
        }
        // set last ',' to ']':
        sb.setCharAt(sb.length() - 1, ']');
        return sb.toString();
    }

    static String shortArray2Json(final short[] array) {
        if (array.length == 0) {
            return "[]";
        }
        final StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (final short o : array) {
            sb.append("\"" + Short.toString(o) + "\"");
            sb.append(',');
        }
        // set last ',' to ']':
        sb.setCharAt(sb.length() - 1, ']');
        return sb.toString();
    }

    static String byteArray2Json(final byte[] array) {
        if (array.length == 0) {
            return "[]";
        }
        final StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (final byte o : array) {
            sb.append("\"" + Byte.toString(o) + "\"");
            sb.append(',');
        }
        // set last ',' to ']':
        sb.setCharAt(sb.length() - 1, ']');
        return sb.toString();
    }

    public static String object2Json(final Object bean) {
        //数据检查
        if (bean == null) {
            return "{}";
        }
        final Method[] methods = bean.getClass().getMethods(); //方法数组
        final StringBuilder sb = new StringBuilder();
        sb.append('{');

        for (final Method method : methods) {
            try {
                final String name = method.getName();
                String key = "";
                if (name.startsWith("get")) {
                    key = name.substring(3);

                    //防死循环
                    final String[] arrs =
                            {"Class"};
                    boolean bl = false;
                    for (final String s : arrs) {
                        if (s.equals(key)) {
                            bl = true;
                            continue;
                        }
                    }
                    if (bl) {
                        continue; //防死循环
                    }
                } else if (name.startsWith("is")) {
                    key = name.substring(2);
                }
                if (key.length() > 0 && Character.isUpperCase(key.charAt(0)) && method.getParameterTypes().length == 0) {
                    if (key.length() == 1) {
                        key = key.toLowerCase();
                    } else if (!Character.isUpperCase(key.charAt(1))) {
                        key = key.substring(0, 1).toLowerCase() + key.substring(1);
                    }
                    final Object elementObj = method.invoke(bean);

                    //System.out.println("###" + key + ":" + elementObj.toString());

                    sb.append('\"');
                    sb.append(key.toUpperCase()); //不能包含特殊字符
                    sb.append('\"');
                    sb.append(':');
                    sb.append(toJson(elementObj)); //循环引用的对象会引发无限递归
                    sb.append(',');
                }
            } catch (final Exception e) {
                //e.getMessage();
                throw new RuntimeException("在将bean封装成JSON格式时异常：" + e.getMessage(), e);
            }
        }
        if (sb.length() == 1) {
            return bean.toString();
        } else {
            sb.setCharAt(sb.length() - 1, '}');
            return sb.toString();
        }
    }
}
